using System;
using System.IO;
using System.Linq;

using Hang.Blog.EntityFrameworkCore;
using Hang.Blog.Localization;
using Hang.Blog.MultiTenancy;
using Hang.Blog.Web.Menus;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;

using Volo.Abp;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper;
using Volo.Abp.Identity.Web;
using Volo.Abp.Json;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.TenantManagement.Web;
using Volo.Abp.UI.Navigation;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem;

namespace Hang.Blog.Web {
    [DependsOn(
        typeof(BlogHttpApiModule),
        typeof(BlogApplicationModule),
        typeof(BlogEntityFrameworkCoreDbMigrationsModule),
        typeof(AbpAutofacModule),
        typeof(AbpIdentityWebModule),
        typeof(AbpAccountWebIdentityServerModule),
        typeof(AbpAspNetCoreMvcUiBasicThemeModule),
        typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
        typeof(AbpTenantManagementWebModule),
        typeof(AbpAspNetCoreSerilogModule),
        typeof(AbpSwashbuckleModule)
        )]
    public class BlogWebModule : AbpModule {

        private const string DefaultCorsPolicy = "Default";
        public override void PreConfigureServices(ServiceConfigurationContext context) {
            Configure<AbpEndpointRouterOptions>(options => {
                options.EndpointConfigureActions.Add(endpointContext => {
                    //endpointContext.Endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
                    endpointContext.Endpoints.MapControllerRoute("default", "index.html");

                });
            });
            PreConfigure<AbpJsonOptions>(options => {
                //options.UseHybridSerializer = false;

            });
            context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options => {
                options.AddAssemblyResource(
                    typeof(BlogResource),
                    typeof(BlogDomainModule).Assembly,
                    typeof(BlogDomainSharedModule).Assembly,
                    typeof(BlogApplicationModule).Assembly,
                    typeof(BlogApplicationContractsModule).Assembly,
                    typeof(BlogWebModule).Assembly
                );
            });
            var configuration = context.Services.GetConfiguration();

            var arry = configuration["App:CorsOrigins"]
                               .Split(",", StringSplitOptions.RemoveEmptyEntries)
                               .Select(o => o.RemovePostFix("/"))
                               .ToArray();


            context.Services.AddCors(options => {
                options.AddPolicy(DefaultCorsPolicy, builder => {
                    builder
                        .AllowAnyOrigin()//添加这个
                        .WithAbpExposedHeaders()
                        .SetIsOriginAllowedToAllowWildcardSubdomains()
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                    //.AllowCredentials(); 去掉这个
                });
            });

        }

        public override void ConfigureServices(ServiceConfigurationContext context) { 
            var hostingEnvironment = context.Services.GetHostingEnvironment();
            var configuration = context.Services.GetConfiguration();

            ConfigureUrls(configuration);
            ConfigureBundles();
            ConfigureAuthentication(context, configuration);
            ConfigureAutoMapper();
            ConfigureVirtualFileSystem(hostingEnvironment);
            ConfigureLocalizationServices();
            ConfigureNavigationServices();
            ConfigureAutoApiControllers();
            ConfigureSwaggerServices(context.Services);
            ConfigureMvc(context, configuration);
            ConfigureDateTime();


        }
        private void ConfigureDateTime() {
            Configure<MvcNewtonsoftJsonOptions>(options => {
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";//对类型为DateTime的生效
            });
            Configure<AbpJsonOptions>(options =>
            options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss" //对类型为DateTimeOffset生效
            );
        }
        private void ConfigureMvc(ServiceConfigurationContext context, IConfiguration configuration) {
            context.Services.AddMvc(t => {

            });
            context.Services.AddControllersWithViews(options => {
                options.EnableEndpointRouting = false;

            });


        }

        private void ConfigureUrls(IConfiguration configuration) {
            Configure<AppUrlOptions>(options => {

                options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
            });
        }

        private void ConfigureBundles() {
            Configure<AbpBundlingOptions>(options => {
                options.StyleBundles.Configure(
                    BasicThemeBundles.Styles.Global,
                    bundle => {
                        bundle.AddFiles("/global-styles.css");
                    }
                );
            });
        }

        private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) {
            context.Services.AddAuthentication()
                .AddJwtBearer(options => {
                    options.Authority = configuration["AuthServer:Authority"];
                    options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
                    options.Audience = "Blog";


                    options.TokenValidationParameters = new TokenValidationParameters {
                        ValidateAudience = false
                    };

                    IdentityModelEventSource.ShowPII = true;

                });
        }

        private void ConfigureAutoMapper() {
            Configure<AbpAutoMapperOptions>(options => {
                options.AddMaps<BlogWebModule>();
            });
        }

        private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment) {
            if (hostingEnvironment.IsDevelopment()) {
                Configure<AbpVirtualFileSystemOptions>(options => {
                    options.FileSets.ReplaceEmbeddedByPhysical<BlogDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Hang.Blog.Domain.Shared"));
                    options.FileSets.ReplaceEmbeddedByPhysical<BlogDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Hang.Blog.Domain"));
                    options.FileSets.ReplaceEmbeddedByPhysical<BlogApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Hang.Blog.Application.Contracts"));
                    options.FileSets.ReplaceEmbeddedByPhysical<BlogApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Hang.Blog.Application"));
                    options.FileSets.ReplaceEmbeddedByPhysical<BlogWebModule>(hostingEnvironment.ContentRootPath);
                });
            }
        }

        private void ConfigureLocalizationServices() {
            Configure<AbpLocalizationOptions>(options => {
                options.Languages.Add(new LanguageInfo("ar", "ar", "العربية"));
                options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));
                options.Languages.Add(new LanguageInfo("en", "en", "English"));
                options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));
                options.Languages.Add(new LanguageInfo("fr", "fr", "Français"));
                options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));
                options.Languages.Add(new LanguageInfo("ru", "ru", "Русский"));
                options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
                options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
                options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));
                options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de"));
                options.Languages.Add(new LanguageInfo("es", "es", "Español"));
            });
        }

        private void ConfigureNavigationServices() {
            Configure<AbpNavigationOptions>(options => {
                options.MenuContributors.Add(new BlogMenuContributor());
            });
        }

        private void ConfigureAutoApiControllers() {
            Configure<AbpAspNetCoreMvcOptions>(options => {
                options.ConventionalControllers.Create(typeof(BlogApplicationModule).Assembly);
            });
        }

        private void ConfigureSwaggerServices(IServiceCollection services) {
            services.AddSwaggerGen(
                options => {
                    options.SwaggerDoc("v1", new OpenApiInfo { Title = "Blog API", Version = "v1" });
                    options.DocInclusionPredicate((docName, description) => true);
                    options.CustomSchemaIds(type => type.FullName);
                }
            );
        }

        public override async void OnApplicationInitialization(ApplicationInitializationContext context) {
            var app = context.GetApplicationBuilder();
            var env = context.GetEnvironment();
            //var ser = app.ApplicationServices.GetService<IUserAppService>();
            //await ser.Info();


            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }

            app.UseAbpRequestLocalization();

            if (!env.IsDevelopment()) {
                app.UseErrorPage();
            }

            app.UseCors(DefaultCorsPolicy);
            app.UseCorrelationId();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseJwtTokenMiddleware();

            if (MultiTenancyConsts.IsEnabled) {
                app.UseMultiTenancy();
            }

            app.UseIdentityServer();
            app.UseAuthorization();
            app.UseSwagger();
            app.UseAbpSwaggerUI(options => {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "Blog API");
            });
            app.UseAuditing();
            app.UseAbpSerilogEnrichers();
            app.UseConfiguredEndpoints();

            app.UseMvc(routes => {
                routes.MapRoute(
                    name: "default",
                    template: "{controller}/{action}/{id?}",
                    defaults: new { controller = "Home", action = "about" }
                );
            });

            app.UseMvcWithDefaultRoute();
        }
    }
}
